﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Ipc;
using System.Runtime.Remoting.Lifetime;
using System.Text;
using System.Threading.Tasks;
using System.Windows;

namespace NicoView.SingleProcess
{
    public sealed class SingleProcessControler
    {
        public  RemoteObject RemoteObject { get; private set; }

        public IpcServerChannel ServerChannel { get; private set; }



        private SingleProcessControler()
        {
        }

        public  bool StartServer(string portName, string uri)
        {

            try
            {
                ServerChannel = new IpcServerChannel(portName);
            }
            catch (RemotingException)
            {
                return false;
            }
            ChannelServices.RegisterChannel(ServerChannel, true);
            RemoteObject = new RemoteObject();
            RemotingServices.Marshal(RemoteObject, uri, typeof(RemoteObject));
            return true;
        }

        public  void StartClient(string portName, string uri)
        {
            IpcClientChannel clientChannel = new IpcClientChannel();
            ChannelServices.RegisterChannel(clientChannel, true);
            RemoteObject = (RemoteObject)Activator.GetObject(typeof(RemoteObject), string.Format("ipc://{0}/{1}", portName, uri));
        }

        public  bool IsFirstInstance()
        {
            string portName = Assembly.GetExecutingAssembly().GetName().Name;
            const string uri = "NicoViewApp";

            if (StartServer(portName, uri))
            {
                return true;
            }
            else
            {
                AllowSetForegroundWindow();
                StartClient(portName, uri);
                RemoteObject.Send(Parameter.GetParameters());
                return false;
            }
        }

        [DllImport("user32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        static extern bool SetForegroundWindow(IntPtr hWnd);
        [DllImport("user32.dll")]
        static extern bool AllowSetForegroundWindow(int dwProcessId);



        public  void WindowActivate(Window window)
        {
            if (window == null) throw new ArgumentNullException();
            IntPtr handle = new System.Windows.Interop.WindowInteropHelper(window).Handle;
            if (handle == IntPtr.Zero) throw new ArgumentException();

            if (window.WindowState == WindowState.Minimized) window.WindowState = WindowState.Normal;
            window.Activate();
            SetForegroundWindow(handle);
        }

        public  void AllowSetForegroundWindow()
        {
            const int ASFW_ANY = -1;
            AllowSetForegroundWindow(ASFW_ANY);
        }
        public static readonly SingleProcessControler Instance = new SingleProcessControler();
    }

    public sealed class RemoteObject : MarshalByRefObject
    {
        public override object InitializeLifetimeService()
        {
            var lease = (ILease)base.InitializeLifetimeService();
            if (lease.CurrentState == LeaseState.Initial)
            {
                lease.InitialLeaseTime = TimeSpan.Zero;
            }
            return lease;
        }

        public class RemoteEventArgs : EventArgs
        {
            public ICollection<string> CommandArgs { get; set; }
            public RemoteEventArgs(ICollection<string> args)
            {
                this.CommandArgs = args;
            }
        }

        public delegate void RemoteEventHandler(object sender, RemoteEventArgs e);
        public event RemoteEventHandler Received;

        public void Send(ICollection<string> args)
        {
            var handle = this.Received;
            if (handle != null)
            {
                handle(null, new RemoteEventArgs( args));
            }
        }
    }
}
